package cn.gson.financial.controller;

import ch.qos.logback.core.util.TimeUtil;
import cn.gson.financial.annotation.IgnoresLogin;
import cn.gson.financial.annotation.PassTokenValid;
import cn.gson.financial.annotation.TokenValid;
//import cn.gson.financial.kernel.aliyuncs.SmsService;
import cn.gson.financial.kernel.constans.ComprehensiveParamesConstans;
import cn.gson.financial.kernel.constans.ContansConfig;
import cn.gson.financial.kernel.controller.JsonResult;
import cn.gson.financial.kernel.exception.ResultCode;
import cn.gson.financial.kernel.model.entity.User;
import cn.gson.financial.kernel.model.entity.UserAccountLimit;
import cn.gson.financial.kernel.model.vo.CheckLoginVo;
import cn.gson.financial.kernel.model.vo.UpdateUserPhoneVo;
import cn.gson.financial.kernel.model.vo.UserVo;
import cn.gson.financial.kernel.service.*;
import cn.gson.financial.kernel.utils.*;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;

//import static cn.gson.financial.kernel.aliyuncs.SmsService.SmsBody;


@Slf4j
@RestController
@RequiredArgsConstructor
public class AppController {

    private final UserService userService;

//    private final SmsService smsService;

    private final UserAccountLimitService userAccountLimitService;

    @Autowired
    private WxService wxService;
    @Autowired
    private RedisUtil redisUtil;

    @Value("${aliyun.sms.signature}")
    private String smsSignature;

    @Value("${aliyun.sms.template-code.verification}")
    private String verificationCode;

    @Value("${aliyun.sms.template-code.register}")
    private String registerCode;
    @Value("$redis.user.ticket_fxy}")
    private String userTicketFtm;
    @Value("${redis.userId.ftm}")
    private String userIdFtm;
    @Value("${redis.user.sessionId}")
    private String sessionId;
    @Autowired
    private RedisCacheManager redisCacheManager;
    @Autowired
    private RedisTemplate redisTemplate;

    private static final Logger logger = LoggerFactory.getLogger(AppController.class);


    /**
     * 扫码_真票靓回调接口_传递微信推送
     *
     * @return
     */
    @IgnoresLogin
    @PostMapping("/wxResult")
    public void fs(@RequestBody Map<String, Object> map) {
        String redisUserTicketKey = userTicketFtm;
        String redisUserOpenIdKey = userIdFtm;
        logger.info("微信回调接口返回值:" + map);
        String userOpenId = (String) map.get("FromUserName");
        String event = (String) map.get("Event");
        String ticket = (String) map.get("Ticket");
        // subscribe: 新关注用户  ; SCAN: 单纯的扫码事件
        // 不管是 新用户还是老用户  或者是 系统未发布 先前关注过的用户 全部先进行 是否落库查询, 没有落库
        //就继续落库 然后登录, 已经落库的 不管, 然后继续登录
        if("subscribe".equals(event) || "SCAN".equals(event)){
            LambdaQueryWrapper<User> qw = Wrappers.lambdaQuery();
            qw.eq(User::getOpenId, userOpenId);
            if (this.userService.count(qw) == 0) { //未落库
                User user = new User();
                user.setOpenId(userOpenId);
                //说明是新用户，需要拿到渠道号存入数据库
                if("subscribe".equals(event)){
                    user.setChannel("记账软件");
                }
                this.userService.save(user);
                UserAccountLimit accountLimit = new UserAccountLimit();
                accountLimit.setUserOpenId(userOpenId);
                userAccountLimitService.saveBean(accountLimit);
            }

            //设置登录时间
            LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper
                    .eq(User::getOpenId, userOpenId)
                    .set(User::getLoginTime, new Date());
            this.userService.update(null, lambdaUpdateWrapper);

            redisCacheManager.set(redisUserTicketKey+ticket, "", 10 * 60);
            redisCacheManager.set(redisUserOpenIdKey+ticket, userOpenId, 60);
        }

    }

    @IgnoresLogin
    @PostMapping("/updateUserPhone")
    @TokenValid
    public JsonResult updateUserPhoneByOpenId(@RequestBody UpdateUserPhoneVo vo){
        boolean flag = userService.updateUserPhoneByOpenId(vo.getPhone(), vo.getOpenId());
        if(flag){
            return JsonResult.successful();
        }
        return JsonResult.failure();
    }

    /**
     * 用于检测扫码和关注状态
     * @return
     */
    @IgnoresLogin
    @PostMapping("/checkLogin")
    @ResponseBody
    public JsonResult checkLogin(@RequestBody CheckLoginVo checkLoginVo, HttpServletRequest request,HttpSession session){


        //预先获取 请求用户的IP地址
        String ip = "";
        try {
            ip = IPUtil.getIP(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String ticket = BaseUtil.checkValueIsNull(checkLoginVo.getTicket());
        if(ticket.equals("")){
            return JsonResult.failure("false");
        }
        //redis 的key
        String redisUserTicketKey = userTicketFtm;
        String redisUserOpenIdKey = userIdFtm;
        String userIdSessionHashKey = sessionId;

        //如果redis中有ticket凭证则说明用户已扫码
        String s = BaseUtil.checkValueIsNull(ticket);
        s = redisUserTicketKey + s;

        System.out.println("useridTicketkey: " + s);
        if(redisCacheManager.hasKey(s)){

            //扫码通过则删除
            redisCacheManager.delete(s);
            Map map = new HashMap();
            String uid = (String) redisCacheManager.get(redisUserOpenIdKey + ticket);
            UserVo userVo = userService.selectUser(uid);
            //更新 Session 中的用户信息
            redisUtil.setAttribute(userVo,session);
            // 组装签发对象
            String sessionId = IdCreateUtil.createSessionId();
            String audience = userVo.getOpenId() + "*" + ip +"*" + sessionId;
            String token = JWTUtil.createToken(audience, userVo.getOpenId(), "PC");
            String redisHashValue = ip +"*" + sessionId;
            //相当于扫码登录，直接加redis
            redisTemplate.opsForHash().put(userIdSessionHashKey,userVo.getOpenId(),redisHashValue);

            map.put("token", token);
            map.put("userInfo", userVo);
            map.put("sessionId",sessionId);

            return JsonResult.successful(map);
        }
        return JsonResult.failure("false");
    }

    /**
     * 获取二维码参数
     * @return
     */
    @IgnoresLogin
    @GetMapping("/getQrCode")
    @ResponseBody
    public JsonResult getQrCode(){
        return JsonResult.successful(wxService.getQrCode());
    }



//    @IgnoresLogin
//    @RequestMapping
//    public JsonResult index() {
//        System.out.println("3");
//        return JsonResult.successful().setMsg("纷析云财务");
//    }



    /**
     * 登录
     *
     * @param mobile
     * @param password
     * @return
     */
    @IgnoresLogin
    @PostMapping("/login")
    public JsonResult login(String mobile, String password, HttpSession session) {
        UserVo user = userService.login(mobile, password);
        //更新 Session 中的用户信息
        redisUtil.setAttribute(user,session);
        return JsonResult.successful();
    }
    /**
     * 登录
     *
     * @param mobile
     * @param password
     * @return
     */
    @IgnoresLogin
    @PostMapping("/loginTest")
    public JsonResult loginTest(String mobile, String password, HttpSession session,HttpServletRequest request) {
        //预先获取 请求用户的IP地址
        String ip = "";
        try {
            ip = IPUtil.getIP(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String userIdSessionHashKey = sessionId;
        Map map = new HashMap();
        UserVo user = userService.login(mobile, password);


        // 组装签发对象
        String sessionId = IdCreateUtil.createSessionId();
        String audience = user.getOpenId() + "*" + ip +"*" + sessionId;
        String token = JWTUtil.createToken(audience, user.getOpenId(), "PC");
        String redisHashValue = ip +"*" + sessionId;
        //相当于扫码登录，直接加redis
        redisTemplate.opsForHash().put(userIdSessionHashKey,user.getOpenId(),redisHashValue);

        map.put("token", token);
        map.put("userInfo", user);
        map.put("sessionId",sessionId);

        redisUtil.setAttribute(user,session);
        return JsonResult.successful(map);
    }



    /**
     * 登出
     *
     * @return
     */
    @GetMapping("/logout")
    public JsonResult logout(HttpSession session) {
        session.invalidate();
        return JsonResult.successful();
    }

    /**
     * 注册
     *
     * @param mobile
     * @return
     */
    @IgnoresLogin
    @PostMapping("/register")
    public JsonResult register(String mobile, String code, HttpSession session) {
        LambdaQueryWrapper<User> qw = Wrappers.lambdaQuery();
        qw.eq(User::getMobile, mobile);
        if (this.userService.count(qw) > 0) {
            return JsonResult.failure("此手机号已被注册，请直接用这个手机号登录或者更换手机号注册！");
        }

        session.removeAttribute(mobile);

        User user = new User();
        user.setMobile(mobile);
        user.setRealName(mobile);
        user.setInitPassword("123456");
        user.setPassword("123456");
        this.userService.save(user);

        redisUtil.setAttribute( this.userService.getUserVo(user.getId()),session);
        try {
        } catch (Exception e) {
            log.error("密码短信发送失败！", e);
        }
        return JsonResult.successful();
    }

    /**
     * 更新个人设置
     *
     * @param realName、email
     * @return
     */
    @PostMapping("/updateUser")
    public JsonResult updateUser(String realName, String email, @SessionAttribute(value = "user", required = false) UserVo user, HttpSession session) {
        user.setRealName(realName);
        user.setEmail(email);
        userService.updateById(user);
        session.setAttribute("user", user);
        return JsonResult.successful();
    }

    /**
     * 重置密码
     *
     * @param newPassword
     * @param repeatPassword
     * @param mobile
     * @param code
     * @param session
     * @return
     */
    @IgnoresLogin
    @PostMapping("/resetPassword")
    public JsonResult resetPassword(@RequestParam String newPassword,
                                    @RequestParam String repeatPassword,
                                    @RequestParam String mobile,
                                    @RequestParam String code, HttpSession session) {
        JsonResult result = JsonResult.instance(true);

        if (!code.equals(session.getAttribute(mobile))) {
            result = JsonResult.failure("验证码错误！");
        } else if (!newPassword.equals(repeatPassword)) {
            result = JsonResult.failure("密码设置错误！");
        }

        if (result.isSuccess()) {
            LambdaQueryWrapper<User> qw = Wrappers.lambdaQuery();
            qw.eq(User::getMobile, mobile);
            User user = userService.getOne(qw);
            if (user != null) {
                user.setPassword(DigestUtils.sha256Hex(newPassword));
                user.setInitPassword("");
                userService.updateById(user);

                session.removeAttribute(mobile);
            } else {
                result = JsonResult.failure("用户不存在！");
            }
        }

        return result;
    }

    /**
     * 修改密码
     *
     * @param original、newPassword
     * @return
     */
    @PostMapping("/updatePwd")
    public JsonResult updatePwd(String original, String newPassword, @SessionAttribute(value = "user", required = false) UserVo user, HttpSession session) {
        //核对旧密码
        User u = userService.getById(user.getId());
        if (!DigestUtils.sha256Hex(original).equals(u.getPassword())) {
            return JsonResult.failure("原密码错误!");
        }

        //更新新密码
        user.setPassword(DigestUtils.sha256Hex(newPassword));
        user.setInitPassword("");
        userService.updateById(user);
        return JsonResult.successful();
    }

    /**
     * 修改手机号码
     *
     * @param verificationCode，mobile
     * @return
     */
    @PostMapping("/changePhoneNumber")
    public JsonResult changePhoneNumber(String verificationCode, String mobile, @SessionAttribute(value = "user", required = false) UserVo user, HttpSession session) {
        //Session里获取手机号对应验证码进行比对
        if (!verificationCode.equals(session.getAttribute(mobile))) {
            return JsonResult.failure("验证码错误!");
        }

        //更新手机号
        user.setMobile(mobile);
        userService.updateById(user);
        redisUtil.setAttribute( user,session);
        return JsonResult.successful();
    }

    /**
     * 变更默认账套
     *
     * @param accountSetsId
     * @param user
     * @param session
     * @return
     */
    @GetMapping("/changeAccountSets")
    public JsonResult changeAccountSets(Integer accountSetsId, @SessionAttribute(value = "user", required = false) UserVo user, HttpSession session) {
        if (user.getAccountSetsList().stream().anyMatch(accountSets -> accountSets.getId().equals(accountSetsId))) {
            user.setAccountSetsId(accountSetsId);
            userService.updateById(user);
            redisUtil.setAttribute(userService.getUserVo(user.getId()),session);
        }
        return JsonResult.successful();
    }

}
